package com.zb.frame.base.config.shiro;

import com.zb.frame.base.enums.AuthenticationStatus;
import com.zb.frame.base.model.AuthUserInfo;
import com.zb.frame.base.model.ClaimsResult;
import com.zb.frame.base.utils.JWTUtil;
import com.zb.frame.modules.sys.service.MenuService;
import com.zb.frame.modules.sys.service.UserService;
import io.jsonwebtoken.Claims;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;

@Component
public class ShiroRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(ShiroRealm.class);

    @Autowired
    UserService userService;

    @Autowired
    MenuService menuService;

    /**
     * 设置 Realm 只支持 SelfToken
     * @return
     */
//    @Override
//    public Class getAuthenticationTokenClass() {
//        return SelfToken.class;
//    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof SelfToken;
    }

    /**
     * 执行授权逻辑-授权资源
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取从登录认证传来的主体
        AuthUserInfo principal = (AuthUserInfo) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(principal.getRole());
        info.addStringPermissions(principal.getPermission());
        // System.out.println("授权资源完成......");
        return info;
    }

    /**
     * 执行认证逻辑-登录认证(解析token是否合法)
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String accessToken = (String) authenticationToken.getPrincipal();
        // System.out.println("---doGetAuthenticationInfo---accessToken---" + accessToken);
        AuthUserInfo userInfo = new AuthUserInfo(); // 传入授权逻辑的用户信息对象
        // JWT token 解析
        ClaimsResult result = JWTUtil.parseToken(accessToken);
        if (result.getCode() == AuthenticationStatus.SUCCESS) {
            Claims  claims = (Claims) result.getData();
            Long userId = Long.parseLong(claims.getSubject()); // 获得用户Id
            // 根据用户Id获取用户信息(状态和角色列表)
            Map<String, Object> stateAndRole = userService.getUserStateAndRoles(userId);
            Integer status = (Integer) stateAndRole.get("state");
            if (status == 2) {
                // 用户被锁
                throw new AuthenticationException(AuthenticationStatus.LOCKED.name());
            } else if (status == 0){
                // 用户被禁用
                throw new AuthenticationException(AuthenticationStatus.DISABLED.name());
            }
            Set<String> roles = (Set<String>) stateAndRole.get("roles");
            userInfo.setUserId(userId);
            userInfo.setRole(roles);
            userInfo.setPermission(menuService.getUserPermission(roles));
        } else {
            // token 解析失败，抛出异常给过滤器捕抓处理
            throw new AuthenticationException(result.getCode().name());
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userInfo, Boolean.TRUE, super.getName());
        // System.out.println("登录认证完成......");
        return info;
    }
}
